/*
 * @Author: your name
 * @Date: 2021-01-21 18:24:25
 * @LastEditTime: 2021-07-27 19:14:30
 * @LastEditors: hgx
 * @Description: In User Settings Edit
 * @FilePath: \electronSerialport\main.js
 */
const log = require('electron-log')

log.transports.file.fileName = 'serialport_client.log'
log.transports.console.level = 'silly'
log.transports.file.level = true; //是否输出到 日志文件
log.transports.console.level = true; //是否输出到 控制台

log.info('process.versions.electron' + process.versions.electron)
log.info('process.versions.modules' + process.versions.modules)
log.info('process.versions.node' + process.versions.node)
log.info('process.versions.v8' + process.versions.v8)
log.info('process.versions.chrome' + process.versions.chrome)
log.info('process.env.PROCESSOR_ARCHITECTURE' + process.env.PROCESSOR_ARCHITECTURE)

const { app, BrowserWindow, dialog, screen } = require('electron')

const SerialPort = require('serialport');
const fs = require("fs");
var loginWin
var mainWin

// let pathConfig = "./resources/app/config.json"
let pathConfig = "./config.json"

/** 读取配置文件 */
var CONF;
try {
  CONF = JSON.parse(fs.readFileSync(pathConfig, 'utf-8'))
  log.info(JSON.stringify(CONF))
} catch (err) {
  log.error("Configuration file read failed")
  app.quit()
  return
}

var reboot = false
function createLoginWin() {
  var {width, height} = screen.getPrimaryDisplay().workAreaSize
  if(width > 950) width = 950
  var cheight = 3 / 4 * width;
  
  if (cheight < height) {
    height = cheight;
  }
  
  loginWin = new BrowserWindow({
    width: width,
    height: height,
    resizable: false,
    webPreferences: {
      nodeIntegration: false
    },
    show: false
  })
  loginWin.removeMenu();
  loginWin.loadFile('./src/login.html')
  // loginWin.openDevTools()
}

function createMainWin(width, height, resizable) {
  mainWin = new BrowserWindow({
    width: width,
    height: height,
    resizable,
    backgroundColor: '#2e2c29',
    webPreferences: {
      nodeIntegration: false
    },
    show: true
  })
  mainWin.removeMenu();
  mainWin.loadFile('./src/index.html')
  // mainWin.openDevTools()
  mainWin.on('close', function () {
    //主窗口关闭的时候必须将webscoket关闭
    //当服务关闭时触发该事件，如果有任何一个 connection 保持链接，都不会触发该事件
    //所以在关闭webscoket时候一定要保持没有客户端与它连接,否则关闭不了
    webconn.close();
  })

  mainWin.on('closed', function () {
    loginWin.close();
  })
}

// app.whenReady().then(createLoginWin)

const getTheLock = app.requestSingleInstanceLock()
if (!getTheLock) {
  app.quit()
  return
} else {
  app.on('second-instance', (event, commandLine, workingDirectory) => {
    if (loginWin) {
      if (loginWin.isMinimized()) loginWin.restore()
      loginWin.focus()
    }
    if (mainWin) {
      if (mainWin.isMinimized()) mainWin.restore()
      mainWin.focus()
    }
  }) 
  app.on('ready', createLoginWin)
}

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
    if (reboot) { //重新启动
      app.relaunch()
    }
  }
})

var showMessageBox = function (win, message) {
  dialog.showMessageBox(win, {
    type: 'info',
    title: '提示信息',
    message: message
  })
}

/** 创建本地 http 服务, 监听串口通信并发送客户端 */
var webconn
var http = require('http')
function createServer() {
  let resJSON = {code:String, msg:Object, status:Number}
  webconn = http.createServer()
  webconn.on("request", function (req, res) {
    switch (req.url) {
      case "loggin":
        res.writeHead(200, {"Content-Type": "application/json"});
        res.write(JSON.stringify())
        break;
    
      default:
        break;
    }   
    res.end()
  }).listen(CONF.SCOKET_PORT, () => { log.info("http 服务器启动成功") })
}


var curPort;
var serialPortData = ""     //用于接收并整合串口数据
var buffer = new Array()
function operPort(port, open, fail) {
  log.log("create connet for com" + port)
  curPort = new SerialPort('com' + port, {
    baudRate: 115200,
    autoOpen: true,
    stopBits: 1,
    dataBits: 8,
    parity: 'none',
    highWaterMark: 1000
  }, false)

  curPort.open(function () {
    log.log("open connet for com" + port)
    curPort.on('data', function (data) {
      data.forEach(item => { buffer.push(item) })
      serialPortData += data
      // console.warn(serialPortData)      
    }).on('error', () => {
      log.log("open connet com" + port + " fail")
      fail()
    })
    open()
  })
}

/** 封装发送串口命令的数据包 */
var csend = function (buff, success) {
  serialPortData = ''
  curPort.write(buff, function (err) {
    setTimeout(() => {
      var res = serialPortData.toString();
      log.info(res)
      success(res.trim())
    }, 500)
  })
}

/** 循环遍历每个串口设备， 连接检测正确的设备 */
function test_port(ports, csend, fail) {
  ports.forEach(item => { console.log(item.path + ' ') })
  if (!ports && ports.length == 0) {
    // 没有检测到设备
    fail()
    return
  }

  var port_size = ports.length
  var port_index = 0
  //异步循环调用检测串口 
  var test_conn_message = function () {
    dialog.showMessageBox(loginWin, {
      type: 'info',
      title: '提示信息',
      message: "没有检测到设备"
    }).then(res => {
      loginWin.close()
    })
  }

  var test_conn = function () {
    if (port_index >= port_size) {
      // 没有检测到网关设备
      test_conn_message()
      return
    }
    const dvicnum = ports[port_index].path.slice(3)
    log.log("order " + port_index, "com" + dvicnum)
    var test_conn_do = function () {
      csend(getbuff(CONF.CODE_GDCNUM), (res) => {
        if (res && res.indexOf("##[FIRST]##") != -1) {
          loginWin.show()
          //开启webscoket
          createServer()
          return
        }
        port_index++
        test_conn()
      })
    }
    operPort(dvicnum, test_conn_do, () => {
      port_index++
      test_conn()
    })
  }
  test_conn()
}


/** 检测串口设备 */
SerialPort.list().then(ports => {
  //循环链接每一台设备 并判断是那一台是当前设备
  test_port(ports, csend, () => {
    loginWin.hide()
    showMessageBox(loginWin, "没有检测到设备")
    loginWin.close()
  })
}).catch(err => {
  log.info(err)
  log.info('列举串口失败')
})


var savePath
function exitsfile(msg, per, number, success) {
  var date = new Date()
  var cfile = savePath
  if (!fs.existsSync(cfile)) { fs.mkdirSync(cfile) }
  cfile = cfile + per + "_" + date.getTime() + "_" + number
  fs.writeFile(cfile, msg, 'utf-8', (res) => {
    success(res, cfile)
  })
}

function split_res(str) {
  const start = str.indexOf(CONF.DEVICE_DATA_START)
  const end = str.indexOf(CONF.DEVICE_DATA_END)

  if (-1 != start && -1 != end) {
    return str.slice(start + CONF.DEVICE_DATA_START.length, end).trim()
  }
  log.info("#ERR_DATA: " + str);
  return '';
}

function getbuff(code, ...para) {
  var len = 0;
  var flag = '';
  var val = '';
  para.forEach(item => {
    val += item
    len += item.length
  })
  if (len < 10) {
    flag = '000' + len
  } else if (len < 100) {
    flag = '00' + len
  } else if (len < 1000) {
    flag = '0' + len
  } else {
    flag = len
  }
  log.info(code + flag + val)
  return code + flag + val
}

/** 补位操作 */
function covering(str, inter) {
  var val = '';
  var str1 = str.split(" ")
  for (var i = 0; i < str1.length; i++) {
    var item = str1[i];
    if (item.length == 1) {
      item = '0' + item
    }
    val += inter + item
  }
  return val.trim()
}

/** 封装数据对象 res eg: 1 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 2 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61  */
function packdata(res, success) {
  var cdata = []
  var obj;
  for (let i = 0, j = 0; i < res.length; i++) {
    if (i % 31 === 0) {
      obj = {}
      obj.number = res[i]
      obj.name = []
    }
    else { obj.name.push(res[i]) }

    if ((i + 1) % 31 === 0) {
      log.info(JSON.stringify(obj))
      cdata.push(obj)
    }
  }
  success(cdata);
}
